import os
import re
import magic
import httpx
import random, ssl
import io
import subprocess
from urllib.parse import urlparse
from PIL import Image, ExifTags,ImageDraw,ImageFont
import pillow_avif
from requests_toolbelt.multipart.encoder import MultipartEncoder
import pyautogui  # Replace pyperclip with pyautogui for sending keys
import tornado.ioloop
import tornado.web
import tornado.gen
import asyncio
import logging
import namegen as n

# Configure logging
logging.basicConfig(level=logging.DEBUG)

# Define the upload folder path
UPLOAD_FOLDER = './pics'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
    
# Define an in-memory data store for storing the current room
data_store = {'current_room': 'chad'}
data_store_lock = asyncio.Lock()

# Function to check if a file is allowed to be uploaded
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

# Function to compress an image
def compress_image(image):
    with io.BytesIO() as output:
        image = image.convert('RGB')
        image.save(output, format="JPEG", quality=40, optimize=True)
        contents = output.getvalue()
    return contents

# Function to compress an image without resizing
def compress_image_raw(image):
    with io.BytesIO() as output:
        image = image.convert('RGB')
        image.save(output, format="JPEG", quality=100, subsampling=0)
        contents = output.getvalue()
    return contents

with open('sessionid.txt', 'r') as f:
    sessionid = f.read()
async def upload_dickpic(slugstr, buffer_pic_data):
    async with httpx.AsyncClient(cookies={'agreeterms': '1', 'sessionid': sessionid}) as client:
        response = await client.get("https://chaturbate.com/emoticons/")
        pattern = r'name="csrfmiddlewaretoken" value="([a-zA-Z0-9]+)"'
        match = re.search(pattern, response.text)
        if not match:
            logging.error("CSRF token not found")
            return False
        csrfmiddlewaretoken = match.group(1)
        mime = magic.Magic(mime=True)
        mime_type = mime.from_buffer(buffer_pic_data)
        m = MultipartEncoder(
            fields={
                'csrfmiddlewaretoken': csrfmiddlewaretoken,
                'slug': slugstr,
                'image': ('image.jpg', buffer_pic_data, mime_type),
                'category': str(1),
                'suggested_category': str()
            }
        )
        headers = {
            'origin': 'https://chaturbate.com',
            'content-type': m.content_type,
            'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
        }
        # Log headers and cookies for debugging
        logging.debug(f"Headers: {headers}")
        logging.debug(f"Cookies: {client.cookies}")
        r = await client.post('https://chaturbate.com/emoticons/', data=m.to_string(), headers=headers)
        if r.status_code == 302 and 'upload_complete' in r.headers.get('location', ''):
            print(slugstr)
            return True
        elif r.status_code == 403:
            logging.error("403 Forbidden: Check CSRF token, cookies, and headers.")
            logging.error(f"Response: {r.text}")
            return False
        else:
            logging.error(f"Unexpected status code: {r.status_code}")
            logging.error(f"Response: {r.text}")
            return False

# Function to play a beep sound
def play_beep(frequency=440, duration=1, volume=10):
    command = f'ffplay -nodisp -autoexit -f lavfi -i "sine=frequency={frequency}:duration={duration}" -volume {volume}'
    subprocess.Popen(command, shell=True)

# Function to send a file extension
def send_ext(filename):
    return filename.rsplit('.', 1)[1].lower()

def addSexualComment(image):    # Get image dimensions
     # Get image dimensions
    image_width, image_height = image.size
    
    # Initialize ImageDraw
    draw = ImageDraw.Draw(image)
    
    # Define your text components
    room_name = data_store.get('current_room')
    text_before_room = "Hopefully you like this @"
    text_after_room = room_name
    
    # Load a font
    font_size = int(image_height * 0.05)  # Start with 5% of the image height
    font = ImageFont.truetype("ariel.otf", font_size)  # Ensure the font path is correct
    
    # Calculate the size of each text component
    text_before_bbox = draw.textbbox((0, 0), text_before_room, font=font)
    text_before_width = text_before_bbox[2] - text_before_bbox[0]
    
    text_after_bbox = draw.textbbox((0, 0), text_after_room, font=font)
    text_after_width = text_after_bbox[2] - text_after_bbox[0]
    
    total_text_width = text_before_width + text_after_width
    total_text_height = max(text_before_bbox[3] - text_before_bbox[1], text_after_bbox[3] - text_after_bbox[1])
    
    # If the total text is too wide, reduce the font size until it fits
    while total_text_width > image_width - 20:  # Leave some padding (20 pixels total)
        font_size -= 1
        font = ImageFont.truetype("ariel.otf", font_size)  # Update font with new size
        
        text_before_bbox = draw.textbbox((0, 0), text_before_room, font=font)
        text_before_width = text_before_bbox[2] - text_before_bbox[0]
        
        text_after_bbox = draw.textbbox((0, 0), text_after_room, font=font)
        text_after_width = text_after_bbox[2] - text_after_bbox[0]
        
        total_text_width = text_before_width + text_after_width
        total_text_height = max(text_before_bbox[3] - text_before_bbox[1], text_after_bbox[3] - text_after_bbox[1])
    
    # Calculate position for the combined text
    x_position = (image_width - total_text_width) / 2
    y_position = image_height - total_text_height - 10
    
    # Draw the first part of the text in white
    draw.text((x_position, y_position), text_before_room, font=font, fill="white")
    
    # Draw the room name in red
    x_position += text_before_width
    draw.text((x_position, y_position), text_after_room, font=font, fill="red")
    
    return image

# Function to handle EXIF orientation
def handle_exif_orientation(image):
    exif = image._getexif()
    if exif is not None:
        orientation_tag = None
        for orientation in ExifTags.TAGS.keys():
            if ExifTags.TAGS[orientation] == 'Orientation':
                orientation_tag = orientation
                break
        if orientation_tag is not None and orientation_tag in exif:
            orientation = exif[orientation_tag]
            if orientation == 3:
                return image.rotate(180, expand=True)
            elif orientation == 6:
                return image.rotate(270, expand=True)
            elif orientation == 8:
                return image.rotate(90, expand=True)
    return image

async def run_command(command):
    # subprocess.run(command, shell=True)
    await asyncio.to_thread(subprocess.run, command, shell=True)

async def save_image_async(image, path, quality=60):
    await asyncio.to_thread(image.save, path, quality=quality)

async def upload_image(image, slugstr):
    async with httpx.AsyncClient() as client:
        with io.BytesIO() as output:
            image.save(output, format="JPEG")
            contents = output.getvalue()
        files = {'file': ('image.jpg', contents, 'image/jpeg')}
        data = {'msg': f":{slugstr} @{data_store.get('current_room')}"}
        response = await client.post("http://opc:2525/upload_image", files=files, data=data)

        if response.status_code == 200:
            print("Image uploaded successfully!")

class BeepHandler(tornado.web.RequestHandler):
    async def get(self):
        play_beep(duration=0.05, volume=60)
        self.write("")

class WebRTCHandler(tornado.web.RequestHandler):
    async def get(self):
        self.set_header('Access-Control-Allow-Origin', '*')
        self.render('camtest.html', name="")

class UploadFileHandler(tornado.web.RequestHandler):
    def options(self):
        self.set_status(204)
        self.set_header('Access-Control-Allow-Origin', '*')
        self.set_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.set_header('Access-Control-Allow-Headers', 'Content-Type')
        self.finish()
    async def get(self):
        self.set_header('Access-Control-Allow-Origin', '*')
        self.render('index.html', name="")

    async def post(self):
        self.set_header('Access-Control-Allow-Origin', '*')
        async with data_store_lock:
            current_room = data_store.get('current_room')
            files = self.request.files.get('file')
            if not files:
                self.write("No file part")
                return

            file = files[0]
            if file.filename == '':
                self.write("No selected file")
                return

            if file and allowed_file(file.filename):
                slugstr = "penis" + "".join([n.generate_nickname() for _ in range(2)])
                filename = slugstr + "." + send_ext(file.filename)
                img = Image.open(io.BytesIO(file.body))
                img = handle_exif_orientation(img)
                # img = addSexualComment(img)
                tiny_img = compress_image(img)
                raw_img_flipped = Image.open(io.BytesIO(compress_image_raw(img)))
 
                results = await asyncio.gather(*[upload_dickpic(slugstr=slugstr, buffer_pic_data=tiny_img)])

                if any(results):
                    filepath_to_save_avif = os.path.join(UPLOAD_FOLDER, slugstr + ".avif")
                    # unused pyautogui.write(":" + slugstr + " ")  # Use pyautogui to simulate keypress instead of pyperclip
                    await run_command("echo 'type :"+slugstr+" ' | dotool")
                    play_beep(duration=0.05, volume=60)
                    # unused await run_command("echo key ctrl+v | dotool")
                    await save_image_async(raw_img_flipped, filepath_to_save_avif)
                    await upload_image(raw_img_flipped, slugstr)
                    self.redirect("/" + slugstr, status=302)
                    return

        self.render('index.html', name="")

class ShowSlugHandler(tornado.web.RequestHandler):
    async def get(self, name):
        self.render('index.html', name=name)

class SetRoomHandler(tornado.web.RequestHandler):
    async def post(self):
        data = tornado.escape.json_decode(self.request.body)
        parsed_url = urlparse(data['url'])
        if parsed_url.netloc != "chaturbate.com":
            self.write("not chaturbate")
            return

        path = parsed_url.path
        path_parts = path.strip('/').split('/')

        async with data_store_lock:
            data_store['current_room'] = path_parts[0]
        print(path_parts[0])

        self.write("")

class DownloadFileHandler(tornado.web.RequestHandler):
    async def get(self, name):
        file_path = os.path.join(UPLOAD_FOLDER, name)
        if os.path.exists(file_path):
            self.set_header('Content-Type', 'application/octet-stream')
            self.set_header('Content-Disposition', f'attachment; filename={name}')
            with open(file_path, 'rb') as f:
                while chunk := f.read(1024 * 1024):
                    self.write(chunk)
            self.finish()
        else:
            self.set_status(404)
            self.write("File not found")

class SendKeysHandler(tornado.web.RequestHandler):
    async def get(self):
        command = "{ echo mouseto 0.5 0.5; echo click; echo click left; echo key enter; sleep 1; echo key left; } | dotool"
        await run_command(command)
        self.write("")

class SendCockEnterKeysHandler(tornado.web.RequestHandler):
    async def get(self):
        command = "echo key enter | dotool"
        await run_command(command)
        referer = self.request.headers.get('Referer', '/')
        self.redirect(referer)

class FaviconHandler(tornado.web.RequestHandler):
    async def get(self):
        self.set_status(204)
        self.finish()

def make_app():
    return tornado.web.Application([
        (r"/a", BeepHandler),
        (r"/b", WebRTCHandler),
        (r"/sendkeys", SendKeysHandler),
        (r"/sendcock_enter", SendCockEnterKeysHandler),
        (r"/telemetry", SetRoomHandler),
        (r"/", UploadFileHandler),
        (r"/([a-zA-Z0-9]+)", ShowSlugHandler),
        (r"/uploads/(.*)", DownloadFileHandler),
        (r"/favicon.ico", FaviconHandler),
    ], template_path="templates", static_path="static")


if __name__ == "__main__":
    app = make_app()
    app.listen(5000)
    tornado.ioloop.IOLoop.current().start()
